import { SendOutlined } from "@ant-design/icons"
import { Button, Form, Input, Space } from "antd"
import { useForm } from "antd/es/form/Form"
import React, { memo, useEffect, useMemo, useState } from "react"

import type { PlasmoMessaging } from "@plasmohq/messaging"
import { useMessage, usePort } from "@plasmohq/messaging/hook"

import { useOIMsg } from "~hook/useOIMsg"
import ChatView from "~maincontent/ChatView/ChatView"
import { useChatStore } from "~store/chatStore"
import { useTokenStroe } from "~store/tokenStore"
import { useUIcontentStore } from "~store/uicontentStore"
import type {
  ChatMessageBaseType,
  ChatMessageType,
  ChatQueryType
} from "~type/chatType"
import { getCurrentTimestamp } from "~util"
import { OIAItypeObj } from "~util/AIUtil"

const MainChatView = memo(() => {
  const aiSource = useTokenStroe((state) => state.tokenType.aiSource)
  const chatPort = usePort<ChatQueryType, ChatMessageType>("chat")
  //全部对话数据
  const _contents = useChatStore((state) => state.contents)

  const getContents = useChatStore((state) => state.getContents)
  const setContents = useChatStore((state) => state.setContents)
  const setChat = useChatStore((state) => state.setChat)
  const chat = useChatStore((state) => state.chat)

  const [message, contextHolder] = useOIMsg()
  const [msgform] = useForm()
  const [isSubmit, setIsSubmit] = useState(false)
  const [_btnDisable, setBtnDisable] = useState(false)
  const btnDisable = useMemo(() => _btnDisable, [_btnDisable])
  const token = useTokenStroe((state) => state.accessToken.access_token)

  const [_isend, setIsend] = useState(false)
  const beforeTime = getCurrentTimestamp() - 1 * 60 * 60 * 1000
  //缓存两个小时对话数据
  const contents = useMemo(
    () => getContents({ timestamp: beforeTime }),
    [_contents]
  )
  const isend = useMemo(() => {
    // console.log("update isend state")
    return _isend
  }, [_isend])

  const onMsgInput = (values: { msg: string }) => {
    console.log("message input finish ")
    if (isSubmit) {
      if (!values.msg && !values.msg) {
        message.error("msg not empty!")
        return
      }
      const data = { content: values.msg, role: "user" }
      const newcontent = [..._contents, data]
      setContents(newcontent)
      setIsSubmit(false)
    }
  }
  const onSendMsg = () => {
    setIsSubmit(true)
    console.log("sendMsg")
    msgform.submit()
  }
  const handle: PlasmoMessaging.Handler<
    "chat-message",
    ChatMessageType,
    any
  > = async (req, res) => {
    if (req.name === "chat-message") {
      const msg = req.body
      // console.log("msg", msg)
      if (msg && msg.error_code) {
        setBtnDisable(false)
        message.error(`${msg.error_code}: ${msg.error_msg}`)
      } else if (msg && msg.error) {
        setBtnDisable(false)
        message.error(`${msg.error.code}: ${msg.error.message}`)
      } else {
        const resdata: any = await parseChatJSON(
          msg,
          contents,
          chat,
          aiSource
        ).catch((err) => {
          setBtnDisable(false)
          message.error(`${err.message}`)
        })
        switch (resdata.aisource) {
          case OIAItypeObj.baidu.type:
            if (Array.isArray(resdata.data)) {
              setContents([...resdata.data])
            } else {
              setContents([..._contents, resdata.data])
            }
            if (resdata.isend) {
              setIsend(true)
              setBtnDisable(false)
            }
            break
          case OIAItypeObj.chatgpt.type:
            setChat(resdata.data)
            // console.log("newchat", resdata.data)

            if (resdata.isend && resdata.data.role) {
              setIsend(true)
              setChat()
              setBtnDisable(false)
              setContents([..._contents, resdata.data])
            }
            break
        }
      }
    }
  }
  useMessage<ChatMessageType, any>(handle)

  //send to background chatMsg
  useEffect(() => {
    // setLoading(false)
    // console.log(e)
    if (isSubmit && contents.length > 0) {
      const data: ChatQueryType = {
        messages: contents,
        stream: true
      }
      if (aiSource === OIAItypeObj.chatgpt.type) {
        data.model = "gpt-3.5-turbo-16k"
      } else {
        data.accessToken = token
      }
      console.log(data)

      chatPort.send(data)
      setBtnDisable(true)
      setIsend(false)
      msgform.resetFields()
    }
    // setIsSubmit(false)
  }, [_contents])
  return (
    <div className="w-full h-full  flex flex-col">
      {contextHolder}
      <div className=" w-full overflow-hidden">
        <ChatView isend={isend}></ChatView>
      </div>
      {token ? (
        <div className="p-[.25rem] mt-auto w-full">
          <Form name="msgForm" form={msgform} onFinish={onMsgInput}>
            <Form.Item name="msg" className="mb-0">
              <Space.Compact style={{ width: "100%" }}>
                <Input
                  disabled={btnDisable}
                  type="text"
                  onPressEnter={onSendMsg}></Input>
                <Button
                  disabled={btnDisable}
                  onClick={onSendMsg}
                  loading={btnDisable}
                  icon={<SendOutlined></SendOutlined>}></Button>
              </Space.Compact>
            </Form.Item>
          </Form>
        </div>
      ) : (
        <></>
      )}
    </div>
  )
})
export default MainChatView
/**
 *
 * @param msg  后端对话端口
 * @param setBtnDisable  是否禁止按钮
 * @param setIsend  是否结束
 * @param contents  对话聊天内容
 * @param setContents  对话聊天内容设置
 * @param aisource ai 来源
 */
async function parseChatJSON(
  msg: ChatMessageType,
  contents: ChatMessageType[],
  chat: ChatMessageBaseType,
  aisource: string
) {
  return new Promise(async (resolve, reject) => {
    try {
      if (msg && msg.id) {
        switch (aisource) {
          case OIAItypeObj.baidu.type:
            const resdata: any = parseChatBaiduJSONtype(msg, contents)

            resolve({ aisource, data: resdata, isend: msg.is_end })
            break
          case OIAItypeObj.chatgpt.type:
            const { data, isEnd } = await parseChatGptJSONtype(msg).catch(
              (err) => {
                console.error(err)
              }
            )
            // console.log("resultdata", data)
            const newChat = { ...chat }
            newChat.role = data && data.role
            newChat.content =
              (newChat && newChat.content ? newChat.content : "") + data.content
            resolve({ aisource, data: newChat, isend: isEnd })

            break
        }
      }
    } catch (err) {
      reject(err)
    }
  })
}
/**
 *
 * @param chatPort
 * @param contents
 * @param setContents
 */
async function parseChatGptJSONtype(msg: ChatMessageType) {
  return new Promise<any>((reslove, reject) => {
    // console.log("choices", msg.choices)
    try {
      msg.choices.forEach((item) => {
        const content =
          item.delta && item.delta.content != undefined
            ? item.delta.content
            : ""
        const data = { content: content, role: "assistant" }
        const isEnd =
          item.finish_reason === "stop" || item.finish_reason === "length"
        // console.log("chatgpt_isend", isEnd)
        reslove({ data: data, isEnd })
      })
    } catch (err) {
      reject(err)
    }
  })
}

/**
 *
 * @param chatPort
 * @param contents
 * @param setContents
 */
function parseChatBaiduJSONtype(
  msg: ChatMessageType,
  contents: ChatMessageType[]
) {
  const data = { content: msg.result, role: "assistant" }

  if (contents[contents.length - 1].role === "user") {
    return data
    // setContents([...contents, data])
  } else {
    const result = contents[contents.length - 1]
    result.content = result.content + msg.result
    contents[contents.length - 1] = result
    return contents
    // setContents([...contents])
  }
}
